#include "stdafx.h"
#include "ASN1ObjectIdentifier.h"

namespace AppliedCryptography
{
	ASN1ObjectIdentifier::ASN1ObjectIdentifier(ClassBits classBits, ConstructedBit constucted, TypeNumberBits number)
		: ASN1Encodable(classBits, constucted, number)
	{
	};

	ASN1ObjectIdentifier::ASN1ObjectIdentifier(ClassBits classBits, ConstructedBit constucted, TypeNumberBits number, const std::string& value)
		: ASN1Encodable(classBits, constucted, number),
		_value(value)
	{
	};

	ASN1ObjectIdentifier::ASN1ObjectIdentifier(ClassBits classBits, ConstructedBit constucted, TypeNumberBits number, const char* value)
		: ASN1Encodable(classBits, constucted, number),
		_value(value)
	{
	};


	ASN1ObjectIdentifier::ASN1ObjectIdentifier()
		: ASN1Encodable(Universal, Primitive, ObjectIdentifier),
		_value("1.1")
	{
	};

	ASN1ObjectIdentifier::ASN1ObjectIdentifier(const std::string& value)
		: ASN1Encodable(Universal, Primitive, ObjectIdentifier),
		_value(value)
	{
	};

	ASN1ObjectIdentifier::ASN1ObjectIdentifier(const char* value)
		: ASN1Encodable(Universal, Primitive, ObjectIdentifier),
		_value(value)
	{
	};


	void ASN1ObjectIdentifier::set(const std::string& value)
	{
		_value = value;
	};

	void ASN1ObjectIdentifier::set(const char* value)
	{
		_value = value;
	};

	void ASN1ObjectIdentifier::operator=(const std::string& value)
	{
		this->set(value);
	};

	void ASN1ObjectIdentifier::operator=(const char* value)
	{
		this->set(value);
	};


	std::string ASN1ObjectIdentifier::get() const
	{
		return _value;
	};


	std::vector<byte> ASN1ObjectIdentifier::getContentBits() const
	{
		std::vector<byte> buffer;
		std::vector<unsigned long> numbers = this->parseIdComponents();
		std::vector<byte> component;

		if(numbers.size() < 3)
		{
			throw std::exception("Too few components for OID;");
		};

		// First two components
		buffer.push_back(40 * numbers[0] % 256 + numbers[1] % 256);

		for(unsigned int i=2; i < numbers.size(); ++i)
		{
			component = this->encodeComponents(numbers[i]);
			buffer.insert(buffer.end(), component.begin(), component.end());
		};

		return buffer;
	};

	std::vector<byte> ASN1ObjectIdentifier::encodeComponents(unsigned long component) const
	{
		std::vector<byte> vComponent;
		int val = component;
		bool fLastByte = true;

		while(val > 128)
		{
			vComponent.insert(vComponent.begin(), val % 128);
			if(!fLastByte)
			{
				vComponent[0] |= 0x80;
			};
			val = (val - val % 128) / 128;
			fLastByte = false;
		};
		if(fLastByte)
		{
			vComponent.insert(vComponent.begin(), val);
		}
		else
		{
			vComponent.insert(vComponent.begin(), val | 0x80);
		};

		return vComponent;
	};

	std::vector<unsigned long> ASN1ObjectIdentifier::parseIdComponents() const
	{
		std::vector<unsigned long> numbers;
		int start = 0, end;
		std::string snum;
		unsigned long num;

		do
		{
			end = _value.find('.', start);
			snum = _value.substr(start, end - start);

			std::stringstream sstream(snum);
			sstream >> num;

			numbers.push_back(num);

			start = end + 1;
		}while(end != std::string::npos);

		return numbers;
	};
	
}; // namespace AppliedCryptography

